package com.eastfair.venueservice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eastfair.boot.request.PageParams;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.constant.BusinessInnerMsgTemplate;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.context.StaticContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.messagecenter.util.SendMsgUtil;
import com.eastfair.venueservice.consts.CommonConstants;
import com.eastfair.venueservice.dao.ServiceProviderAuditMapper;
import com.eastfair.venueservice.dto.ServiceProviderAuditDTO;
import com.eastfair.venueservice.dto.ServiceProviderAuditHistoryDTO;
import com.eastfair.venueservice.dto.ServiceProviderDTO;
import com.eastfair.venueservice.entity.ServiceProviderAudit;
import com.eastfair.venueservice.enumeration.ServiceProviderAuditAuditResultEnum;
import com.eastfair.venueservice.enumeration.ServiceProviderAuditAuditTypeEnum;
import com.eastfair.venueservice.enumeration.ServiceProviderTypeEnum;
import com.eastfair.venueservice.exceptioncode.VenueServiceExceptionCode;
import com.eastfair.venueservice.service.ServiceProviderAuditHistoryService;
import com.eastfair.venueservice.service.ServiceProviderAuditService;
import com.eastfair.venueservice.service.ServiceProviderService;
import com.eastfair.venueservice.vo.ServiceProviderAuditVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 服务商审核流程表
 * </p>
 *
 * @author gj
 * @date 2022-07-13
 */
@Slf4j
@Service
//@DS("#thread.tenant")
public class ServiceProviderAuditServiceImpl extends SuperServiceImpl<ServiceProviderAuditMapper, ServiceProviderAudit> implements ServiceProviderAuditService {

    @Resource
    private ServiceProviderService serviceProviderService;

    @Resource
    private ServiceProviderAuditHistoryService serviceProviderAuditHistoryService;

    @Resource
    private SendMsgUtil sendMsgUtil;

    @Resource(name = "threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;


    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<ServiceProviderAudit> modelList) {
        modelList.forEach(s -> s.setIsDeleted(BusinessConstant.YES));
        return R.successDef();
    }

    @Override
    protected R<Boolean> handlerSave(ServiceProviderAudit model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        if (model.getAuditResult() == null) {
            model.setAuditResult(ServiceProviderAuditAuditResultEnum.REPORTING);
        }
        if (model.getReportTime() == null) {
            model.setReportTime(LocalDateTime.now());
        }
        return R.successDef();
    }

    @Override
    public IPage<ServiceProviderAuditVO> listServiceProviderAuditVOs(PageParams<ServiceProviderAuditDTO> pageParams) {
        log.info("listServiceProviderAuditVOs - 查询审核VO列表, pageParams={}", pageParams);
        IPage<ServiceProviderAudit> page = listServiceProviderAudits(pageParams);
        IPage<ServiceProviderAuditVO> voPage = new Page<>();
        BeanUtil.copyProperties(page, voPage);
        List<ServiceProviderAudit> records = page.getRecords();
        if (records == null || records.isEmpty()) {
            return voPage;
        }
        List<ServiceProviderAuditVO> serviceProviderAuditVOList = records
                .stream()
                .map(serviceProvider -> BeanUtil.toBean(serviceProvider, ServiceProviderAuditVO.class))
                .collect(Collectors.toList());
        voPage.setRecords(serviceProviderAuditVOList);
        return voPage;
    }

    @Override
    public IPage<ServiceProviderAudit> listServiceProviderAudits(PageParams<ServiceProviderAuditDTO> pageParams) {
        log.info("listServiceProviderAudits - 查询审核列表, pageParams={}", pageParams);
        ServiceProviderAuditDTO query = pageParams.getModel();
        QueryWrapper<ServiceProviderAudit> queryWrapper = createServiceProviderAuditQueryWrapper(query);
        IPage<ServiceProviderAudit> page = pageParams.buildPage();
        return page(page, queryWrapper);
    }

    @Override
    public List<ServiceProviderAudit> listServiceProviderAudits(ServiceProviderAuditDTO param) {
        QueryWrapper<ServiceProviderAudit> queryWrapper = createServiceProviderAuditQueryWrapper(param);
        return list(queryWrapper);
    }

    @Override
    public List<ServiceProviderAudit> listByServiceProviderId(Long serviceProviderId) {
        ServiceProviderAuditDTO param = new ServiceProviderAuditDTO();
        param.setServiceProviderId(serviceProviderId);
        return listServiceProviderAudits(param);
    }

    @Override
    public ServiceProviderAuditVO getServiceProviderAuditVOById(Long id) {
        log.info("getServiceProviderAuditVOById - ID查询审核详情, id={}", id);

        ServiceProviderAudit serviceProviderAudit = getById(id);
        if (serviceProviderAudit == null) {
            throw BizException.wrap(VenueServiceExceptionCode.SERVICE_PROVIDER_AUDIT_NOT_EXIST);
        }
        ServiceProviderAuditVO serviceProviderAuditVO = BeanUtil.toBean(serviceProviderAudit, ServiceProviderAuditVO.class);
        return serviceProviderAuditVO;
    }

    @Override
    public ServiceProviderAudit getAuditingByServiceProviderId(Long serviceProviderId) {
        log.info("getProcessingAuditByServiceProviderId - 服务商ID查询未结束的审核, serviceProviderId={}", serviceProviderId);
        QueryWrapper<ServiceProviderAudit> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .last("limit 1")
                .eq(ServiceProviderAudit::getIsDeleted, BusinessConstant.DELETE_NO)
                .not(query -> query.eq(ServiceProviderAudit::getAuditResult,
                        ServiceProviderAuditAuditResultEnum.APPROVED.getCode()))
                .eq(serviceProviderId != null, ServiceProviderAudit::getServiceProviderId, serviceProviderId);
        return getOne(queryWrapper);
    }

    @Override
    public ServiceProviderAudit getLatestAuditByServiceProviderId(Long serviceProviderId) {
        log.info("getLatestAuditByServiceProviderId - 服务商id获取最近的审核记录, serviceProviderId={}", serviceProviderId);
        QueryWrapper<ServiceProviderAudit> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .last("limit 1")
                .eq(ServiceProviderAudit::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(serviceProviderId != null, ServiceProviderAudit::getServiceProviderId, serviceProviderId)
                .orderByDesc(ServiceProviderAudit::getCreateTime)
        ;
        return getOne(queryWrapper);
    }

    @Override
    public ServiceProviderAudit getFirstAuditByServiceProviderId(Long serviceProviderId) {
        log.info("getFirstAuditByServiceProviderId - 服务商ID查询初审类型的审核, serviceProviderId={}", serviceProviderId);
        QueryWrapper<ServiceProviderAudit> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .last("limit 1")
                .eq(ServiceProviderAudit::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(ServiceProviderAudit::getAuditType, ServiceProviderAuditAuditTypeEnum.FIRST_AUDIT)
                .eq(ServiceProviderAudit::getServiceProviderId, serviceProviderId)
        ;
        return getOne(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveServiceProviderAudit(ServiceProviderAuditDTO auditDTO) {
        log.info("saveServiceProviderAudit - 保存服务商审核记录, auditDTO={}", auditDTO);
        // 如果当前存在审核进行中的服务商信息，则不可新增审核
        ServiceProviderAudit existAudit = getAuditingByServiceProviderId(auditDTO.getServiceProviderId());
        if (existAudit != null) {
            throw BizException.wrap(VenueServiceExceptionCode.REPORTING_SERVICE_PROVIDER_EXIST);
        }
        // 判断是年审/初审
        ServiceProviderAudit firstAudit = getFirstAuditByServiceProviderId(auditDTO.getServiceProviderId());
        auditDTO.setAuditType(ServiceProviderAuditAuditTypeEnum.FIRST_AUDIT);
        if (firstAudit != null) {
            auditDTO.setAuditType(ServiceProviderAuditAuditTypeEnum.YEAR_AUDIT);
        }
        ServiceProviderAudit serviceProviderAudit = BeanUtil.toBean(auditDTO, ServiceProviderAudit.class);
        save(serviceProviderAudit);
        // 发送服务商注册站内信消息提醒
        asyncSendRegisterInnerMsg(serviceProviderAudit);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateServiceProviderAudit(ServiceProviderAuditDTO auditDTO) {
        log.info("updateServiceProviderAudit - 更新服务商审核记录, auditDTO={}", auditDTO);
        ServiceProviderAudit audit = BeanUtil.toBean(auditDTO, ServiceProviderAudit.class);
        return updateById(audit);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateAuditResult(ServiceProviderAuditDTO auditDTO) {
        log.info("updateAuditResult - 更新服务商审核结果, auditDTO={}", auditDTO);
        if (ServiceProviderAuditAuditResultEnum.APPROVED.eq(auditDTO.getAuditResult())
                & (auditDTO.getValidStartTime() == null || auditDTO.getValidEndTime() == null)) {
            throw BizException.validFail("认证有效期开始时间或截止时间不可为空");
        }
        // 更新审核记录的审核结果
        ServiceProviderAudit audit = getById(auditDTO.getId());
        if (audit == null) {
            throw BizException.wrap(VenueServiceExceptionCode.SERVICE_PROVIDER_AUDIT_NOT_EXIST);
        }
        audit.setAuditResult(auditDTO.getAuditResult());
        audit.setAuditOpinion(auditDTO.getAuditOpinion());
        audit.setValidStartTime(auditDTO.getValidStartTime());
        audit.setValidEndTime(auditDTO.getValidEndTime());
        audit.setAuditTime(auditDTO.getAuditTime());
        audit.setAuditUserId(auditDTO.getAuditUserId());
        audit.setAuditUserName(auditDTO.getAuditUserName());
        updateById(audit);
        // 更新服务商的审核状态
        serviceProviderService.updateAuditStatus(auditDTO);
        // 保存审核历史记录
        CopyOptions copyOptions = CopyOptions
                .create()
                .setIgnoreProperties(CommonConstants.COMMON_IGNORE_PROPERTIES);
        ServiceProviderAuditHistoryDTO historyDTO = BeanUtil.toBean(audit, ServiceProviderAuditHistoryDTO.class, copyOptions);
        historyDTO.setServiceProviderAuditId(auditDTO.getId());
        serviceProviderAuditHistoryService.saveServiceProviderAuditHistory(historyDTO);
        if (!ServiceProviderAuditAuditResultEnum.APPROVED.eq(auditDTO.getAuditResult())) {
            return true;
        }
        // 添加角色
        return serviceProviderService.addServiceProviderRole(auditDTO.getServiceProviderType(), auditDTO.getUserId(), auditDTO.getServiceProviderId(), audit.getCompanyName());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateNotApprovedAudit(ServiceProviderDTO serviceProviderDTO) {
        log.info("updateProcessingAudit - 更新审核中的审核记录，将审核结果重置, serviceProviderDTO={}", serviceProviderDTO);
        ServiceProviderAudit processingAudit = getAuditingByServiceProviderId(serviceProviderDTO.getId());
        if (processingAudit == null) {
            throw BizException.wrap(VenueServiceExceptionCode.SERVICE_PROVIDER_AUDIT_NOT_EXIST);
        }
        if (ServiceProviderAuditAuditResultEnum.REPORTING.eq(processingAudit.getAuditResult())) {
            throw BizException.wrap(VenueServiceExceptionCode.SERVICE_PROVIDER_REPORTING_CAN_NOT_UPDATE);
        }
        CopyOptions copyOptions = CopyOptions
                .create()
                .setIgnoreProperties(CommonConstants.COMMON_IGNORE_PROPERTIES);
        BeanUtil.copyProperties(serviceProviderDTO, processingAudit, copyOptions);
        updateById(processingAudit);
        // 将审核结果重置
        UpdateWrapper<ServiceProviderAudit> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda()
                .set(ServiceProviderAudit::getAuditResult, ServiceProviderAuditAuditResultEnum.REPORTING.getCode())
                .set(ServiceProviderAudit::getAuditOpinion, null)
                .set(ServiceProviderAudit::getValidStartTime, null)
                .set(ServiceProviderAudit::getValidEndTime, null)
                .set(ServiceProviderAudit::getAuditTime, null)
                .set(ServiceProviderAudit::getAuditUserId, null)
                .set(ServiceProviderAudit::getAuditUserName, null)
                .set(ServiceProviderAudit::getReportTime, LocalDateTime.now())
                .eq(ServiceProviderAudit::getId, processingAudit.getId())
        ;
        update(updateWrapper);
        // 发送服务商注册站内信消息提醒
        asyncSendRegisterInnerMsg(processingAudit);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean copyBatchNewTypeServiceProviderAudit(Long sourceServiceProviderId, Long targetServiceProviderId, String targetServiceProviderType) {
        log.info("copyNewTypeServiceProviderAudit - 复制服务商审核记录, sourceServiceProviderId={}, targetServiceProviderId={}",
                sourceServiceProviderId, targetServiceProviderId);
        List<ServiceProviderAudit> sourceList = listByServiceProviderId(sourceServiceProviderId);
        if (sourceList == null || sourceList.isEmpty()) {
            return true;
        }
        CopyOptions copyOptions = CopyOptions
                .create()
                .setIgnoreProperties(CommonConstants.COMMON_IGNORE_PROPERTIES);
        List<ServiceProviderAudit> targetList = sourceList
                .stream()
                .map(sourceServiceProviderAudit -> {
                    ServiceProviderAudit newServiceProviderAudit = BeanUtil.toBean(sourceServiceProviderAudit, ServiceProviderAudit.class, copyOptions);
                    newServiceProviderAudit.setServiceProviderId(targetServiceProviderId);
                    return newServiceProviderAudit;
                })
                .collect(Collectors.toList());
        targetList.forEach(newServiceProviderAudit -> {
            if (ServiceProviderAuditAuditResultEnum.REPORTING.eq(newServiceProviderAudit.getAuditResult())) {
                newServiceProviderAudit.setServiceProviderType(targetServiceProviderType);
                // 发送服务商注册消息
                asyncSendRegisterInnerMsg(newServiceProviderAudit);
            }
            save(newServiceProviderAudit);
            // 复制审核历史
            serviceProviderAuditHistoryService
                    .asyncCopyBatchNewAuditHistory(sourceServiceProviderId, targetServiceProviderId, newServiceProviderAudit.getId());
        });
        return true;
    }

    @Override
    public boolean sendRegisterInnerMsg(ServiceProviderAudit serviceProviderAudit) {
        log.info("sendRegisterInnerMsg - 发送服务商注册站内信, serviceProviderAudit={}", serviceProviderAudit);
        if (StrUtil.isBlank(serviceProviderAudit.getServiceProviderType())) {
            throw BizException.wrap(-1, "服务商类型缺失，无法生成发送内容");
        }
        String content;
        if (ServiceProviderTypeEnum.HOME_SERVICE_PROVIDER.getCode().equals(serviceProviderAudit.getServiceProviderType())) {
            content = String.format(BusinessInnerMsgTemplate.SERVICE_PROVIDER_REGISTER_TEMPLATE, "主场", serviceProviderAudit.getCompanyName());
        } else if (ServiceProviderTypeEnum.BUILD_SERVICE_PROVIDER.getCode().equals(serviceProviderAudit.getServiceProviderType())) {
            content = String.format(BusinessInnerMsgTemplate.SERVICE_PROVIDER_REGISTER_TEMPLATE, "搭建商", serviceProviderAudit.getCompanyName());
        } else if (ServiceProviderTypeEnum.MAIN_TRANSPORT_SERVICE_PROVIDER.getCode().equals(serviceProviderAudit.getServiceProviderType())) {
            content = String.format(BusinessInnerMsgTemplate.SERVICE_PROVIDER_REGISTER_TEMPLATE, "主运", serviceProviderAudit.getCompanyName());
        } else if (ServiceProviderTypeEnum.MATCHING_SERVICE_PROVIDER.getCode().equals(serviceProviderAudit.getServiceProviderType())) {
            content = String.format(BusinessInnerMsgTemplate.SERVICE_PROVIDER_REGISTER_TEMPLATE, "配套商", serviceProviderAudit.getCompanyName());
        } else {
            throw BizException.wrap(-1, "服务商类型有误，无法生成发送内容");
        }
        sendMsgUtil.sendInnerMsg(content, StaticContextUtil.getProjectSystemScene());
        return true;
    }

    @Override
    public void asyncSendRegisterInnerMsg(ServiceProviderAudit serviceProviderAudit) {
        threadPoolTaskExecutor.execute(() -> sendRegisterInnerMsg(serviceProviderAudit));
    }

    /**
     * 生成ServiceProviderAudit的QueryWrapper.
     *
     * @param query ServiceProviderAuditDTO.
     * @return QueryWrapper.
     */
    private QueryWrapper<ServiceProviderAudit> createServiceProviderAuditQueryWrapper(ServiceProviderAuditDTO query) {
        QueryWrapper<ServiceProviderAudit> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(ServiceProviderAudit::getIsDeleted, BusinessConstant.DELETE_NO)
                .like(StrUtil.isNotBlank(query.getCompanyName()),
                        ServiceProviderAudit::getCompanyName, query.getCompanyName())
                .like(StrUtil.isNotBlank(query.getPrincipalName()),
                        ServiceProviderAudit::getPrincipalName, query.getPrincipalName())
                .eq(StrUtil.isNotBlank(query.getServiceProviderType()),
                        ServiceProviderAudit::getServiceProviderType, query.getServiceProviderType())
                .eq(query.getAuditType() != null, ServiceProviderAudit::getAuditType, query.getAuditType())
                .eq(query.getAuditResult() != null, ServiceProviderAudit::getAuditResult, query.getAuditResult())
                .eq(query.getServiceProviderId() != null,
                        ServiceProviderAudit::getServiceProviderId, query.getServiceProviderId())
        ;
        return queryWrapper;
    }
}
